namespace ts.td {

    export const enum RecTyKind {
        BitRecTyKind,
        BitsRecTyKind,
        IntRecTyKind,
        StringRecTyKind,
        ListRecTyKind,
        DagRecTyKind,
        RecordRecTyKind
    }

    export interface RecTy {
        Kind: RecTyKind
        ListTy: ListRecTy
        getRecTyKind(): RecTyKind
        getAsString(): string
        print(w: ts.EmitTextWriter): void
        dump(): void
        typeIsConvertibleTo(RHS: RecTy): boolean
        typeIsA(RHS: RecTy): boolean
        getListTy(): ListRecTy
    }

    export interface ListRecTy extends RecTy {
        Kind: RecTyKind.ListRecTyKind
        ElementTy: RecTy
        getElementType(): RecTy
    }

    export interface BitRecTy extends RecTy {
        Kind: RecTyKind.BitRecTyKind
    }

    export interface BitsRecTy extends RecTy {
        Kind: RecTyKind.BitsRecTyKind
        Size: number
        getNumBits(): number
    }

    export interface IntRecTy extends RecTy {
        Kind: RecTyKind.IntRecTyKind
    }

    export interface StringRecTy extends RecTy {
        Kind: RecTyKind.StringRecTyKind
    }

    export interface DagRecTy extends RecTy {
        Kind: RecTyKind.DagRecTyKind
    }

    export interface RecordRecTy extends RecTy {
        Kind: RecTyKind.RecordRecTyKind
        NumClasses: number
        Profile(ID: any /*FoldingSetNodeID*/): void
        getClasses(): Record[]
        isSubClassOf(Class: Record): boolean
    }

    export const enum InitKind {
        IK_First, // unused; silence a spurious warning
        IK_FirstTypedInit,
        IK_BitInit,
        IK_BitsInit,
        IK_DagInit,
        IK_DefInit,
        IK_FieldInit,
        IK_IntInit,
        IK_ListInit,
        IK_FirstOpInit,
        IK_BinOpInit,
        IK_TernOpInit,
        IK_UnOpInit,
        IK_LastOpInit,
        IK_CondOpInit,
        IK_FoldOpInit,
        IK_IsAOpInit,
        IK_AnonymousNameInit,
        IK_StringInit,
        IK_VarInit,
        IK_VarListElementInit,
        IK_VarBitInit,
        IK_VarDefInit,
        IK_LastTypedInit,
        IK_UnsetInit
    };

    export interface Init {
        Kind: InitKind
        Opc: number
        anchor(): void
        getKind(): InitKind
        isComplete(): boolean
        isConcrete(): boolean
        print(w: ts.EmitTextWriter): void
        getAsString(): string
        getAsUnquotedString(): string
        dump(): void
        getCastTo(Ty: RecTy): Init
        onvertInitializerTo(Ty: RecTy): Init
        convertInitializerBitRange(Bits: number[]): Init
        convertInitListSlice(Elements: number[]): Init
        getFieldType(FieldName: string): RecTy
        resolveReferences(R: Resolver): Init
        getBit(Bit: number): Init
    }

    export interface TypedInit extends Init {
        ValueTy: RecTy
        getType(): RecTy
        convertInitializerTo(Ty: RecTy): Init
    }

    export interface UnsetInit extends Init {
        ValueTy: RecTy
        getType(): RecTy
        convertInitializerTo(Ty: RecTy): Init
    }

    export interface BitInit extends TypedInit {
        Value: boolean
        getValue(): boolean
    }

    export interface BitsInit extends TypedInit {
        NumBits: number
        Profile(ID: any /*FoldingSetNodeID*/): void
        getNumBits(): number
        convertInitializerBitRange(Bits: number[]): Init
        allInComplete(): boolean
        resolveReferences(R: Resolver): Init
    }

    export interface IntInit extends TypedInit {
        Value: number
    }

    export interface AnonymousNameInit extends TypedInit {
        Value: number
    }

    export const enum StringFormat {
        SF_String,
        SF_Code
    }

    export interface StringInit extends TypedInit {
        Value: string
        Format: StringFormat
        determineFormat(Fmt1: StringFormat, Fmt2: StringFormat): StringFormat
        getValue(): string
        getFormat(): StringFormat
        hasCodeFormat(): boolean
        getAsUnquotedString(): string
    }

    export interface ListInit extends TypedInit {
        NumValues: number
        Profile(ID: any /*FoldingSetNodeID*/): void
        getElement(): Init
        getElementType(): RecTy
        getElementAsRecord(): Record
        convertInitListSlice(Elements: number[]): Init
        convertInitializerTo(Ty: RecTy): Init
        resolveReferences(R: Resolver): Init
        getValues(): Init[]

    }

    export interface OpInit extends TypedInit {
        clone(): OpInit
        getNumOperands(): number
        getOperand(i: number): Init
    }

    export const enum UnaryOp {
        CAST,
        NOT,
        HEAD,
        TAIL,
        SIZE,
        EMPTY,
        GETDAGOP
    }

    export interface UnOpInit extends OpInit {
        opc: UnaryOp
        LHS: Init
        getNumOperands(): number
        getOpcode(): UnaryOp
        getOperand(i: number): Init
        Fold(CurRec: Record, IsFinal: boolean): Init
        resolveReferences(R: Resolver): Init
        getAsString(): string
    }

    export const enum BinaryOp {
        ADD, SUB, MUL, AND, OR, XOR, SHL, SRA, SRL, LISTCONCAT,
        LISTSPLAT, STRCONCAT, INTERLEAVE, CONCAT, EQ,
        NE, LE, LT, GE, GT, SETDAGOP
    }

    export interface BinOpInit extends OpInit {
        opc: BinaryOp
        LHS: Init
        RHS: Init
    }

    export const  enum TernaryOp { SUBST, FOREACH, FILTER, IF, DAG, SUBSTR, FIND }

    export interface TernOpInit extends OpInit {
        opc: TernaryOp
        LHS: Init
        MHS: Init
        RHS: Init
    }

    export interface CondOpInit extends TypedInit {
        NumConds: number
        ValType: RecTy
        getValType(): RecTy
        getNumConds(): number
        getCond(num: number): Init
        getVal(num: number): Init
        getConds(): Init[]
        getVals(): Init[]
    }


    export interface FoldOpInit extends TypedInit {
        Start: Init
        List: Init
        A: Init
        B: Init
        Expr: Init
    }

    export interface IsAOpInit extends TypedInit {
        CheckType: RecTy
        Expr: Init
    }

    export interface VarInit extends TypedInit {
        VarName: Init
    }


    export interface VarBitInit extends TypedInit {
        TI: TypedInit
        Bit: number
    }


    export interface VarListElementInit extends TypedInit {
        TI: TypedInit
        Element: number
    }

    export interface DefInit extends TypedInit {
        Def: Record
    }

    export interface VarDefInit extends TypedInit {
        Class: Record
        Def: DefInit
        NumArgs: number
    }

    export interface FieldInit extends TypedInit {
        Rec: Init
        FieldName: string
    }

    export interface DagInit extends TypedInit {
        Val: Init
        ValName: string
        NumArgs: number
        NumArgNames: number
    }

    export const enum FieldKind {
        FK_Normal,        // A normal record field.
        FK_NonconcreteOK, // A field that can be nonconcrete ('field' keyword).
        FK_TemplateArg,   // A template argument.
    }

    export interface RecordVal {
        Kind: FieldKind
        Name: Init
        Loc: SMLoc
        Ty: RecTy
        getName(): string
        getNameInit(): Init
        getNameInitAsString(): string
        getLoc(): SMLoc
        isNonconcreteOK(): boolean
        isTemplateArg(): boolean
        getType(): RecTy
        getPrintType(): string
        getValue(): Init
        setValue(V: Init): boolean
        setValue(V: Init, L: SMLoc): boolean
        dump(): void
        print(w: EmitTextWriter, PrintDem: boolean): void
    }

    export interface Record {
        Name: Init
        ID: number;
        Locs: SMLoc[]
        TemplateArgs: Init[]
        Values: RecordVal[]
        Assertions: AssertionInfo[]
        SuperClasses: [Record, SMRange][]
        TrackedRecords: RecordKeeper
        CorrespondingDefInit: DefInit
        IsAnonymous: boolean
        IsClass: boolean
        checkName(): void
        getID(): number
        getName(): string
        getNameInit(): Init
        getNameInitAsString(): string
        setName(Name: Init): void
        getLoc(): SMLoc[]
        appednLoc(Loc: SMLoc): void
        getType(): RecordRecTy
        getDefInit(): DefInit
        getTemplateArgs(): Init[]
        getValues(): RecordVal[]
        getAssertions(): AssertionInfo
        getSuperClasses(): [Record, SMRange][]
        hasDirectSuperClass(SuperClass: Record): boolean
        getDirectSuperClasses(Classes: Record[]): void
        isTemplateArg(Name: Init): boolean
        getValue(Name: Init): RecordVal
        getValue(Name: string): RecordVal
        addTemplateArg(Name: Init): void
        addValue(RV: RecordVal): void
        removeValue(Name: Init): void
        removeValue(Name: string): void
        addAssertion(Loc: SMLoc, Condition: Init, Message: Init): void
        appendAssertions(Rec: Record): void
        checkRecordAssertions(): void
        isSubClassOf(R: Record): boolean
        isSubClassOf(Name: string): boolean
        addSuperClass(R: Record, Range: SMRange): void
        resolveReferences(NewName: Init): void
        resolveReferences(R: Resolver, SkipVal: RecordVal): void
        getRecords(): RecordKeeper
        isAnonymous(): boolean
        dump(): void
        getFieldLoc(FieldName: string): SMLoc
        getValueInit(FieldName: string): Init
        isValueUnset(FieldName: string): boolean
        getValueAsString(FieldName: string): string
        getValueAsOptionalString(FieldName: string): string | undefined
        getValueAsBitsInit(FieldName: string): BitsInit
        getValueAsListInit(FieldName: string): ListInit
        getValueAsListOfDefs(FieldName: string): Record[]
        getValueAsListOfInts(FieldName: string): number[]
        getValueAsListOfStrings(FieldName: string): string[]
        getValueAsDef(FieldName: string): Record
        getValueAsOptionalDef(FieldName: string): Record
        getValueAsBit(FieldName: string): boolean
        getValueAsBitOrUnset(FieldName: string, Unset: boolean): boolean
        getValueAsInt(FieldName: string): boolean
        getValueAsDag(FieldName: string): DagInit
    }

    export interface SMLoc {
        Ptr: number
    }

    export interface SMRange {
        Start: SMLoc
        End: SMLoc
    }

    export interface AssertionInfo {
        Loc: SMLoc
        Condition: Init
        Message: Init
    }

    export interface Resolver {
        CurRec: Record
        IsFinal: boolean
        resolve(VarName: Init): Init
        keepUnsetBits(): boolean
        isFinal(): boolean
        setFinal(Final: boolean): void

    }

    export interface RecordKeeper {
        InputFilename: string
        Classes: Map<Record>
        Defs: Map<Record>
        ClassRecordsMap: Map<Record[]>
        RecordTypePool: Map<RecordRecTy>
        ExtraGlobals: Map<any>
        AnonCounter: number
    }

}